package com.voiceqsologger.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.voiceqsologger.config.LlmApiProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

/**
 * 面试辅导 LLM 客户端：将用户语句发送给模型，快速返回要点提示/回答建议。
 * 强化低温度与短模板，追求低延迟。
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class LlmInterviewCoachClient {

    private final LlmApiProperties props;
    private final RestTemplate restTemplate = new RestTemplate();
    private final ObjectMapper mapper = new ObjectMapper();

    public String suggest(String userUtterance) {
        String apiKey = props.getApiKey();
        if (apiKey == null || apiKey.isEmpty()) apiKey = System.getenv("SILICONFLOW_API_KEY");
        if (apiKey == null || apiKey.isEmpty()) throw new IllegalStateException("未配置 LLM API Key");

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization", "Bearer " + apiKey);

//        String system = "你是一个Java面试辅导助手，输出简短专业回复。";
        String system = "你是一个Java高级开发工程师，下面是一场面试，请输出简短专业面试题回复。";
        String user = "面试问题：\n" + (userUtterance == null ? "" : userUtterance);

        try {
            // 第一次按配置模型名请求
            String body = callOnce(headers, props.getModel(), system, user);
            if (body == null) return null;
            return extractContent(body);
        } catch (org.springframework.web.client.HttpClientErrorException.BadRequest e) {
            // 遇到 400 参数错误，尝试去掉组织前缀的模型名重试（SiliconFlow 某些模型名称不含"Qwen/"前缀）
            try {
                String model = props.getModel();
                String shortModel = (model != null && model.contains("/")) ? model.substring(model.lastIndexOf('/') + 1) : model;
                String body2 = callOnce(headers, shortModel, system, user);
                if (body2 == null) return null;
                return extractContent(body2);
            } catch (Exception ex) {
                log.error("coach retry error", ex);
                return null;
            }
        } catch (Exception e) {
            log.error("coach suggest error", e);
            return null;
        }
    }

    private String callOnce(HttpHeaders headers, String model, String system, String user) {
        try {
            // 使用 Jackson 构造 JSON，避免字符串转义问题（包含 emoji 等）
            var root = mapper.createObjectNode();
            root.put("model", model);
            var messages = root.putArray("messages");
            var sys = mapper.createObjectNode(); sys.put("role", "system"); sys.put("content", system); messages.add(sys);
            var usr = mapper.createObjectNode(); usr.put("role", "user"); usr.put("content", user); messages.add(usr);
            root.put("temperature", 0.1);
            root.put("max_tokens", 128);

            HttpEntity<String> req = new HttpEntity<>(root.toString(), headers);
            ResponseEntity<String> resp = restTemplate.postForEntity(props.getChatUrl(), req, String.class);
            if (!resp.getStatusCode().is2xxSuccessful()) {
                throw new RuntimeException("LLM 调用失败: code=" + resp.getStatusCodeValue() + ", body=" + resp.getBody());
            }
            return resp.getBody();
        } catch (Exception e) {
            throw e;
        }
    }

    private String extractContent(String body) throws Exception {
        JsonNode root = mapper.readTree(body);
        JsonNode choices = root.path("choices");
        if (choices.isArray() && choices.size() > 0) {
            return choices.get(0).path("message").path("content").asText();
        }
        return null;
    }

    private static String escape(String s) {
        if (s == null) return "";
        return s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n");
    }
}


